package com.haizhi.crm.sys.service.impl;

import com.haizhi.crm.sys.bean.*;
import com.haizhi.crm.sys.dao.UserDao;
import com.haizhi.crm.sys.service.IUserService;
import com.querydsl.core.types.Predicate;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private EntityManager entityManager;

    private JPAQueryFactory queryFactory;

    @Autowired
    private UserDao userDao;

    @PostConstruct
    public void initFactory() {
        System.out.println("开始实例化JPAQueryFactory");
        queryFactory = new JPAQueryFactory(entityManager);
    }


    @Override
    public List<User> queryUser(UserQo userQo) {
        QUser qUser = QUser.user;
        QRole qRole = QRole.role;

        List<Predicate> predicates = new ArrayList<Predicate>();

        if (userQo.getUsername() != null && !userQo.getUsername().isEmpty()) {
            predicates.add(qUser.username.like("%" + userQo.getUsername() + "%"));
        }

        if (userQo.getEmail() != null && !userQo.getEmail().isEmpty()) {
            predicates.add(qUser.email.like("%" + userQo.getEmail() + "%"));
        }

        if (userQo.getCar() != null && !userQo.getCar().isEmpty()) {
            predicates.add(qUser.car.like("%" + userQo.getCar() + "%"));
        }

        Predicate[] arr = new Predicate[predicates.size()];


        return queryFactory
                .select(qUser)
                .from(qUser, qRole)
                .where(predicates.toArray(arr))
                .offset(userQo.getPageNo())
                .limit(userQo.getPageSize())
                .fetch();
    }

    @Override
    public User optimizedFind(String id) {
        return userDao.optimizedFindOne(id);
    }

    @Override
    public User find(String id) {
        return userDao.findOne(id);
    }


    public List<User> findUser(UserQo userQo) {
        UserSpecification userSpecification = new UserSpecification();
        Specification<User> specification = userSpecification.build(userQo.getUsername(), userQo.getEmail(), userQo.getCar(), userQo.getRoleNames());
        return userDao.findAll(specification);
    }

}

class UserSpecification implements Specification<User> {

    private String username;

    private String email;

    private String car;

    private String[] roleNames;

    @Override
    public javax.persistence.criteria.Predicate toPredicate(
            Root<User> root,
            CriteriaQuery<?> query,
            CriteriaBuilder builder
    ) {
        List<javax.persistence.criteria.Predicate> predicates = new ArrayList<javax.persistence.criteria.Predicate>();
        if (!StringUtils.isEmpty(this.username)) {
            Path<String> username = root.get("username");
            predicates.add(builder.like(username, "%" + this.username + "%"));
        }
        if (!StringUtils.isEmpty(this.email)) {
            Path<String> email = root.get("email");
            predicates.add(builder.like(email, "%" + this.email + "%"));
        }
        if (!StringUtils.isEmpty(this.car)) {
            Path<String> car = root.get("car");
            predicates.add(builder.like(car, "%" + this.car + "%"));
        }
        if (roleNames != null && roleNames.length > 0) {
            Join<User, Role> roles = root.join("roles");
            Path<String> roleName = roles.get("roleName");
            CriteriaBuilder.In<String> in = builder.in(roleName);
            for (String r : roleNames) {
                in.value(r);
            }
            predicates.add(in);
        }
        return builder.and(predicates.toArray(new javax.persistence.criteria.Predicate[predicates.size()]));
    }

    public UserSpecification build(String username, String email, String car, String[] roleNames) {
        this.username = username;
        this.email = email;
        this.car = car;
        this.roleNames = roleNames;
        return this;
    }

}